home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / hity wydania / Ubuntu 9.10 PL / karmelkowy-koliberek-desktop-9.10-i386-PL.iso / casper / filesystem.squashfs / usr / share / system-config-printer / AdvancedServerSettings.py next >
Text File  |  2009-10-19  |  16KB  |  437 lines

  1. #!/usr/bin/env python
  2.  
  3. ## system-config-printer
  4.  
  5. ## Copyright (C) 2008, 2009 Red Hat, Inc.
  6. ## Copyright (C) 2008, 2009 Tim Waugh <twaugh@redhat.com>
  7.  
  8. ## This program is free software; you can redistribute it and/or modify
  9. ## it under the terms of the GNU General Public License as published by
  10. ## the Free Software Foundation; either version 2 of the License, or
  11. ## (at your option) any later version.
  12.  
  13. ## This program is distributed in the hope that it will be useful,
  14. ## but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16. ## GNU General Public License for more details.
  17.  
  18. ## You should have received a copy of the GNU General Public License
  19. ## along with this program; if not, write to the Free Software
  20. ## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21.  
  22. from gettext import gettext as _
  23. import gobject
  24. import gtk
  25. import os
  26. import socket
  27. import tempfile
  28. import time
  29.  
  30. from errordialogs import *
  31.  
  32. class AdvancedServerSettingsDialog:
  33.     RESOURCE="/admin/conf/cupsd.conf"
  34.  
  35.     def __init__ (self, cupsconn, parent=None, on_apply=None):
  36.         self.cupsconn = cupsconn
  37.         self.on_apply = on_apply
  38.  
  39.         # Signal handler IDs.
  40.         self.handler_ids = {}
  41.  
  42.         dialog = gtk.Dialog (_("Advanced Server Settings"),
  43.                              parent,
  44.                              gtk.DIALOG_MODAL |
  45.                              gtk.DIALOG_DESTROY_WITH_PARENT,
  46.                              (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
  47.                               gtk.STOCK_OK, gtk.RESPONSE_OK))
  48.         dialog.set_default_response (gtk.RESPONSE_OK)
  49.         dialog.set_border_width (6)
  50.         dialog.set_resizable (False)
  51.         dialog.set_has_separator (False)
  52.         self.connect (dialog, 'response', self.on_response)
  53.         self.dialog = dialog
  54.  
  55.         frames_vbox = gtk.VBox (False, 6)
  56.         dialog.vbox.pack_start (frames_vbox, False, False, 0)
  57.  
  58.         history_frame = gtk.Frame ()
  59.         label = gtk.Label ('<b>' + _("Job History") + '</b>')
  60.         label.set_use_markup (True)
  61.         history_frame.set_label_widget (label)
  62.         history_frame.set_shadow_type (gtk.SHADOW_NONE)
  63.         frames_vbox.pack_start (history_frame, False, False, 0)
  64.  
  65.         align = gtk.Alignment (0.5, 0.5, 1.0, 1.0)
  66.         align.set_padding (0, 0, 12, 0)
  67.         history_frame.add (align)
  68.         vbox = gtk.VBox (False, 0)
  69.         align.add (vbox)
  70.         rb1 = gtk.RadioButton (None, _("Do not preserve job history"), False)
  71.         self.rbPreserveJobNone = rb1
  72.         rb2 = gtk.RadioButton (rb1, _("Preserve job history but not files"),
  73.                                False)
  74.         self.rbPreserveJobHistory = rb2
  75.         rb3 = gtk.RadioButton (rb1, _("Preserve job files (allow reprinting)"),
  76.                                False)
  77.         self.rbPreserveJobFiles = rb3
  78.         vbox.pack_start (rb1, False, False, 0)
  79.         vbox.pack_start (rb2, False, False, 0)
  80.         vbox.pack_start (rb3, False, False, 0)
  81.  
  82.         browse_frame = gtk.Frame ()
  83.         label = gtk.Label ('<b>' + _("Browse Servers") + '</b>')
  84.         label.set_use_markup (True)
  85.         browse_frame.set_label_widget (label)
  86.         browse_frame.set_shadow_type (gtk.SHADOW_NONE)
  87.         frames_vbox.pack_start (browse_frame, False, False, 0)
  88.  
  89.         align = gtk.Alignment (0.5, 0.5, 1.0, 1.0)
  90.         align.set_padding (0, 0, 12, 0)
  91.         browse_frame.add (align)
  92.         vbox = gtk.VBox (False, 6)
  93.         align.add (vbox)
  94.         label = gtk.Label (_("Usually print servers broadcast their "
  95.                              "queues.  Specify print servers below "
  96.                              "to periodically ask for queues instead."))
  97.         label.set_line_wrap (True)
  98.         vbox.pack_start (label, False, False, 0)
  99.         hbox = gtk.HBox (False, 6)
  100.         vbox.pack_start (hbox, False, False, 0)
  101.  
  102.         scrollwin = gtk.ScrolledWindow ()
  103.         scrollwin.set_shadow_type (gtk.SHADOW_IN)
  104.         scrollwin.set_policy (gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
  105.         hbox.pack_start (scrollwin, True, True, 0)
  106.         treeview = gtk.TreeView ()
  107.         treeview.set_headers_visible (False)
  108.         scrollwin.add (treeview)
  109.         selection = treeview.get_selection ()
  110.         selection.set_mode (gtk.SELECTION_MULTIPLE)
  111.         self.connect (selection, 'changed', self.on_treeview_selection_changed)
  112.         col = gtk.TreeViewColumn ('', gtk.CellRendererText (), text=0)
  113.         treeview.append_column (col)
  114.         self.browse_treeview = treeview
  115.  
  116.         bb = gtk.VButtonBox ()
  117.         bb.set_layout (gtk.BUTTONBOX_START)
  118.         hbox.pack_start (bb, False, False, 0)
  119.  
  120.         add = gtk.Button (stock=gtk.STOCK_ADD)
  121.         bb.add (add)
  122.         self.connect (add, 'clicked', self.on_add_clicked)
  123.         self.add = add
  124.         remove = gtk.Button (stock=gtk.STOCK_REMOVE)
  125.         remove.set_sensitive (False)
  126.         bb.add (remove)
  127.         self.connect (remove, 'clicked', self.on_remove_clicked)
  128.         self.remove = remove
  129.  
  130.         # Fetch cupsd.conf
  131.         f = tempfile.TemporaryFile ()
  132.         try:
  133.             cupsconn.getFile (self.RESOURCE, file=f)
  134.         except cups.HTTPError, s:
  135.             show_HTTP_Error (s, dialog)
  136.             raise
  137.  
  138.         def parse_yesno (line):
  139.             arg1 = line.split (' ')[1].strip ()
  140.             if arg1 in ['true', 'on', 'enabled', 'yes']:
  141.                 return True
  142.             if arg1 in ['false', 'off', 'disabled', 'no', '0']:
  143.                 return False
  144.             try:
  145.                 if int (arg1) != 0:
  146.                     return True
  147.             except:
  148.                 pass
  149.             raise RuntimeError
  150.  
  151.         preserve_job_history = True
  152.         preserve_job_files = False
  153.         browsing = True
  154.         self.browse_poll = []
  155.         f.seek (0)
  156.         for line in f.readlines ():
  157.             l = line.lower ()
  158.             if l.startswith ("preservejobhistory "):
  159.                 try:
  160.                     preserve_job_history = parse_yesno (l)
  161.                 except:
  162.                     pass
  163.             elif l.startswith ("preservejobfiles "):
  164.                 try:
  165.                     preserve_job_files = parse_yesno (l)
  166.                 except:
  167.                     pass
  168.             elif l.startswith ("browsing "):
  169.                 try:
  170.                     browsing = parse_yesno (l)
  171.                 except:
  172.                     pass
  173.             elif l.startswith ("browsepoll "):
  174.                 self.browse_poll.append (line[len ("browsepoll "):].strip ())
  175.  
  176.         if not browsing:
  177.             browse_frame.set_sensitive (False)
  178.             
  179.         if preserve_job_files:
  180.             self.rbPreserveJobFiles.set_active (True)
  181.         elif preserve_job_history:
  182.             self.rbPreserveJobHistory.set_active (True)
  183.         else:
  184.             self.rbPreserveJobNone.set_active (True)
  185.  
  186.         self.preserve_job_history = preserve_job_history
  187.         self.preserve_job_files = preserve_job_files
  188.  
  189.         model = gtk.ListStore (gobject.TYPE_STRING)
  190.         treeview.set_model (model)
  191.         for server in self.browse_poll:
  192.             model.append (row=[server])
  193.  
  194.         dialog.show_all ()
  195.  
  196.     def connect (self, widget, signal, handler, reason=None):
  197.         id = widget.connect (signal, handler)
  198.         if not self.handler_ids.has_key (reason):
  199.             self.handler_ids[reason] = []
  200.         self.handler_ids[reason].append ((widget, id))
  201.  
  202.     def disconnect (self, reason=None):
  203.         for (widget, id) in self.handler_ids[reason]:
  204.             widget.disconnect (id)
  205.         del self.handler_ids[reason]
  206.  
  207.     def __del__ (self):
  208.         self.dialog.destroy ()
  209.  
  210.     def on_treeview_selection_changed (self, selection):
  211.         self.remove.set_sensitive (selection.count_selected_rows () != 0)
  212.  
  213.     def on_add_clicked (self, button):
  214.         model = self.browse_treeview.get_model ()
  215.         iter = model.insert (0, row=[_("Enter IP address")])
  216.         button.set_sensitive (False)
  217.         col = self.browse_treeview.get_columns ()[0]
  218.         cell = col.get_cell_renderers ()[0]
  219.         cell.set_property ('editable', True)
  220.         self.browse_treeview.set_cursor ((0,), col, start_editing=True)
  221.         self.connect (cell, 'edited', self.on_browse_poll_edited,
  222.                       'edit')
  223.         self.connect (cell, 'editing-canceled', self.on_browse_poll_edit_cancel,
  224.                       'edit')
  225.  
  226.     def on_browse_poll_edited (self, cell, path, newvalue):
  227.         model = self.browse_treeview.get_model ()
  228.         iter = model.get_iter (path)
  229.         model.set_value (iter, 0, newvalue)
  230.         cell.stop_editing (canceled=False)
  231.         cell.set_property ('editable', False)
  232.         self.add.set_sensitive (True)
  233.         self.disconnect ('edit')
  234.  
  235.         valid = True
  236.         # Check that it's a valid IP address or hostname.
  237.         # First, is it an IP address?
  238.         try:
  239.             socket.getaddrinfo (newvalue, '0', socket.AF_UNSPEC, 0, 0,
  240.                                 socket.AI_NUMERICHOST)
  241.         except socket.gaierror:
  242.             # No.  Perhaps it's a hostname.
  243.             labels = newvalue.split (".")
  244.             seen_alpha = False
  245.             for label in labels:
  246.                 if (label[0] == '-' or
  247.                     label.endswith ('-')):
  248.                     valid = False
  249.                     break
  250.                 for char in label:
  251.                     if not seen_alpha:
  252.                         if char.isalpha ():
  253.                             seen_alpha = True
  254.  
  255.                     if not (char.isalpha () or
  256.                             char.isdigit () or
  257.                             char == '-'):
  258.                         valid = False
  259.                         break
  260.  
  261.                 if not valid:
  262.                     break
  263.  
  264.             if valid and not seen_alpha:
  265.                 valid = False
  266.  
  267.         if valid:
  268.             count = 0
  269.             i = model.get_iter_first ()
  270.             while i:
  271.                 if model.get_value (i, 0) == newvalue:
  272.                     count += 1
  273.                     if count == 2:
  274.                         valid = False
  275.                         selection = self.browse_treeview.get_selection ()
  276.                         selection.select_iter (i)
  277.                         break
  278.                 i = model.iter_next (i)
  279.         else:
  280.             model.remove (iter)
  281.  
  282.     def on_browse_poll_edit_cancel (self, cell):
  283.         cell.stop_editing (canceled=True)
  284.         cell.set_property ('editable', False)
  285.         model = self.browse_treeview.get_model ()
  286.         iter = model.get_iter ((0,))
  287.         model.remove (iter)
  288.         self.add.set_sensitive (True)
  289.         self.remove.set_sensitive (False)
  290.         self.disconnect ('edit')
  291.  
  292.     def on_remove_clicked (self, button):
  293.         model = self.browse_treeview.get_model ()
  294.         selection = self.browse_treeview.get_selection ()
  295.         rows = selection.get_selected_rows ()
  296.         refs = map (lambda path: gtk.TreeRowReference (model, path),
  297.                     rows[1])
  298.         for ref in refs:
  299.             path = ref.get_path ()
  300.             iter = model.get_iter (path)
  301.             model.remove (iter)
  302.  
  303.     def on_response (self, dialog, response):
  304.         if (response == gtk.RESPONSE_CANCEL or
  305.             response != gtk.RESPONSE_OK):
  306.             self.disconnect ()
  307.             del self
  308.             return
  309.  
  310.         # See if there are changes.
  311.         preserve_job_files = self.rbPreserveJobFiles.get_active ()
  312.         preserve_job_history = (preserve_job_files or
  313.                                 self.rbPreserveJobHistory.get_active ())
  314.         model = self.browse_treeview.get_model ()
  315.         browse_poll = []
  316.         iter = model.get_iter_first ()
  317.         while iter:
  318.             browse_poll.append (model.get_value (iter, 0))
  319.             iter = model.iter_next (iter)
  320.  
  321.         if (set (browse_poll) == set (self.browse_poll) and
  322.             preserve_job_files == self.preserve_job_files and
  323.             preserve_job_history == self.preserve_job_history):
  324.             self.disconnect ()
  325.             del self
  326.             return
  327.  
  328.         # Fetch cupsd.conf afresh
  329.         f = tempfile.TemporaryFile ()
  330.         try:
  331.             self.cupsconn.getFile (self.RESOURCE, file=f)
  332.         except cups.HTTPError, s:
  333.             show_HTTP_Error (s, dialog)
  334.             return
  335.  
  336.         job_history_line = job_files_line = browsepoll_lines = ""
  337.  
  338.         # Default is to preserve job history
  339.         if not preserve_job_history:
  340.             job_history_line = "PreserveJobHistory No\n"
  341.  
  342.         # Default is not to preserve job files.
  343.         if preserve_job_files:
  344.             job_files_line = "PreserveJobFiles Yes\n"
  345.  
  346.         for server in browse_poll:
  347.             browsepoll_lines += "BrowsePoll %s\n" % server
  348.  
  349.         f.seek (0)
  350.         conf = tempfile.TemporaryFile ()
  351.         wrote_preserve_history = wrote_preserve_files = False
  352.         wrote_browsepoll = False
  353.         has_browsepoll = False
  354.         lines = f.readlines ()
  355.         for line in lines:
  356.             l = line.lower ().strip ()
  357.             if l.startswith ("browsepoll "):
  358.                 has_browsepoll = True
  359.                 break
  360.  
  361.         for line in lines:
  362.             l = line.lower ().strip ()
  363.             if l.startswith ("preservejobhistory "):
  364.                 if wrote_preserve_history:
  365.                     # Don't write out another line with this keyword.
  366.                     continue
  367.                 # Alter this line before writing it out.
  368.                 line = job_history_line
  369.                 wrote_preserve_history = True
  370.             elif l.startswith ("preservejobfiles "):
  371.                 if wrote_preserve_files:
  372.                     # Don't write out another line with this keyword.
  373.                     continue
  374.                 # Alter this line before writing it out.
  375.                 line = job_files_line
  376.                 wrote_preserve_files = True
  377.             elif (has_browsepoll and
  378.                   l.startswith ("browsepoll ")):
  379.                 if wrote_browsepoll:
  380.                     # Ignore extra BrowsePoll lines.
  381.                     continue
  382.                 # Write new BrowsePoll section.
  383.                 conf.write (browsepoll_lines)
  384.                 wrote_browsepoll = True
  385.                 # Don't write out the original BrowsePoll line.
  386.                 continue
  387.             elif (not has_browsepoll and
  388.                   l.startswith ("browsing ")):
  389.                 if not wrote_browsepoll:
  390.                     # Write original Browsing line.
  391.                     conf.write (line)
  392.                     # Write new BrowsePoll section.
  393.                     conf.write (browsepoll_lines)
  394.                     wrote_browsepoll = True
  395.                     continue
  396.  
  397.             conf.write (line)
  398.  
  399.         if not wrote_preserve_history:
  400.             conf.write (job_history_line)
  401.         if not wrote_preserve_files:
  402.             conf.write (job_files_line)
  403.         if not wrote_browsepoll:
  404.             conf.write (browsepoll_lines)
  405.  
  406.         conf.flush ()
  407.         fd = conf.fileno ()
  408.         os.lseek (fd, 0, os.SEEK_SET)
  409.         try:
  410.             self.cupsconn.putFile ("/admin/conf/cupsd.conf", fd=fd)
  411.         except cups.HTTPError, s:
  412.             show_HTTP_Error (s, dialog)
  413.             return
  414.  
  415.         # Give the server a chance to process our request.
  416.         time.sleep (1)
  417.  
  418.         # Now reconnect, in case the server needed to reload.
  419.         try:
  420.             attempt = 1
  421.             while attempt <= 5:
  422.                 try:
  423.                     self.cupsconn._connect ()
  424.                     break
  425.                 except RuntimeError:
  426.                     # Connection failed.
  427.                     time.sleep (1)
  428.                     attempt += 1
  429.         except AttributeError:
  430.             # _connect method is part of the authconn.Connection
  431.             # interface, so don't fail if that method doesn't exist.
  432.             pass
  433.  
  434.         self.disconnect ()
  435.         self.on_apply ()
  436.         del self
  437.